package org.tissou.server.importer.ofx;

import org.tissou.server.importer.ImporteurDeTransactions;
import org.tissou.client.Services.Parametres;
import org.tissou.client.Services.MonException;

import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.ParserConfigurationException;
import java.util.List;
import java.util.Date;
import java.util.ArrayList;
import java.io.InputStream;
import java.io.IOException;
import java.text.SimpleDateFormat;
import java.text.ParseException;

import org.xml.sax.SAXException;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.NodeList;

/**
 * Importe specifiquement les fichiers OFX
 * (HSBC, Barclays, et plein d'autres banques)
 * Utilise la librairie de parsing XML pour ca.
 */
public class ImporteurOFX implements ImporteurDeTransactions {

  protected static final SimpleDateFormat OFX_DATE_FORMAT = new SimpleDateFormat("yyyyMMdd");

  protected InputStream fichier;

  protected Document document = null;

  public ImporteurOFX(InputStream fichierAImporter) {
    fichier = fichierAImporter; 
  }

  public void parser() {
    DocumentBuilderFactory docBuilderFactory = DocumentBuilderFactory.newInstance();
    DocumentBuilder docBuilder = null;
    try {
      docBuilder = docBuilderFactory.newDocumentBuilder();
      InputStream xml = new OFXToXML(fichier);
      document = docBuilder.parse(xml);

      // normalize text representation
      document.getDocumentElement ().normalize ();

    } catch (ParserConfigurationException e) {
      e.printStackTrace();
      throw new MonException("Mauvaise configuration du parser");
    } catch (IOException e) {
      e.printStackTrace();
      throw new MonException("Impossible de lire le fichier.");
    } catch (SAXException e) {
      e.printStackTrace();
      throw new MonException("Erreur XML dans le fichier");
    }
  }
  
  public List<Parametres> toutesLesTransactions() {
    return analyserLeDocument();
  }

  public String identifiantCompte() {
    if (document == null) {
      parser();
    }
    NodeList liste = document.getElementsByTagName("ACCTID");
    if (liste.getLength() != 1) {
      throw new MonException("Il y a un probleme avec le fichier OFX : Je ne trouve" +
          " pas un seul ACCTID.");
    }
    return liste.item(0).getTextContent();
  }

  private List<Parametres> analyserLeDocument() {
    if (document == null) {
      parser();
    }
    List<Parametres> liste = new ArrayList<Parametres>();
    NodeList transactionElements = document.getElementsByTagName("STMTTRN");

    for (int i = 0; i < transactionElements.getLength(); i++) {
      Element transactionElement = (Element) transactionElements.item(i);

      Parametres p = new Parametres();

      p.setDate(getDate(transactionElement));
      p.ajouterLibelle(getLibelle(transactionElement));
      p.ajouterSomme(getMontant(transactionElement));
      liste.add(p);
    }
    return liste;
  }

  private Date getDate(Element transactionElement) {
    Element dateElement = (Element) transactionElement.getElementsByTagName("DTPOSTED").item(0);
    String date = dateElement.getTextContent();
    try {
      return OFX_DATE_FORMAT.parse(date.substring(0, 8));
    } catch (ParseException e) {
      throw new MonException("La date n'est pas correctement formattee");
    }
  }

  private float getMontant(Element transactionElement) {
    Element montantElement = (Element) transactionElement.getElementsByTagName("TRNAMT").item(0);
    String montant = montantElement.getTextContent();
    try {
      return Float.valueOf(montant);
    } catch (NumberFormatException e) {
      throw new MonException("Le montant n'est pas correctement formatte");
    }
  }

  private String getLibelle(Element transactionElement) {
    Element libelleElement = (Element) transactionElement.getElementsByTagName("NAME").item(0);
    return libelleElement.getTextContent(); 
  }
}
